let isiPhone=navigator.userAgent.includes('iPhone');
//后端ws服务地址
// const API_URL='192.168.170.138:8888';
const API_URL='192.168.0.102:8888';
initCssVar();

/**
 * 监听窗口resize
 */
window.addEventListener('resize',debounce(initCssVar))
let userid=localStorage.getItem('uuid');
let userName= localStorage.getItem('roomName')||prompt("请输入您在聊天室中的昵称");
if(!localStorage.getItem('roomName')){
  localStorage.setItem('roomName',userName)
}
generateUUid();
const msgContainer=document.querySelector('.msg_area')
const btn=document.querySelector("button");
const textarea=document.querySelector("textarea");
const imgInput=document.querySelector('.input_img');
const fileBtn=document.querySelector('.add_icon');
const loadTip=document.querySelector('.load_tip');
const roomTotal=document.querySelector('.room_total');
const prevBox=document.querySelector('.preview_bg');
let curentImg="";
initMsgList();

//socket连接
const socket=io(`ws://${API_URL}`);
socket.on("serverToClient",o=>{
  appendMsg([o])
})
socket.on('totalRefresh',n=>{
  roomTotal.innerHTML=`在线${n}人`
})
/**
 * 初始化信息列表
 */
async function initMsgList(){
  try {
    let list=await fetch(`http://${API_URL}/msgList`,{method:"GET"});
    list=await list.json();
    loadTip.style.display="none";
    let len=list.data.length;
    if(len){
        appendMsg(list.data,true);
    }else{
      appendTips();
    }
  } 
  catch (error) {
    alert("数据初始化失败,请检查网络");
  }
  
}
/**
 * 
 * @param {*} a 传入文件的size(以B为大小单位)
 * @param {*} b 返回的size保留的小数位数
 * @returns 最终返回 带单位的size
 */
function formatBytes(a, b) { 
  if (0 == a) return "0 B"; 
  let c = 1024, d = b || 2, e = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], f = Math.floor(Math.log(a) / Math.log(c)); 
  return parseFloat((a / Math.pow(c, f)).toFixed(d)) + " " + e[f];
}
/**
 * input文件选入后的回调  当我们选中图片之后以dataUrl的形式读取存储图片格式
 */
imgInput.addEventListener('change', async(e)=>{
  const MaxImgSize=819200; //800*1024 KB
  let currentFile= e.target.files[0];
  //如果大于800KB进行压缩
  (currentFile.size >MaxImgSize) &&(currentFile = await imgCompress(currentFile))
  let {size} =currentFile;
  size=formatBytes(size);
  textarea.placeholder=`[图片] ${currentFile.name} ${size}`
  let reader=new FileReader();
  reader.addEventListener('load',()=>{
    curentImg=reader.result;
  },false);
  reader.readAsDataURL(currentFile)
})
/**
 * 点击加号图标调用文件上传
 */
fileBtn.addEventListener('click',()=>{
  imgInput.click();
})

// 键盘事件处理相关区域 (此处优化交互, enter 为发送   enter+ shift为换行)
const targetKeys=['shift','enter']
let CaputredKeys=[];//捕获到的key
/**
 * 文本域按键按下事件用于捕获按下的键位
 */
textarea.addEventListener('keydown',(e)=>{
  let key=e.key.toLocaleLowerCase()
  if(targetKeys.includes(key)){
    CaputredKeys.push(key)
  }
})
/**
 * 文本域keyUp事件
 * @param {Event} e keyUp事件对象
 */
textarea.addEventListener('keyup',(e)=>{
  // e.preventDefault();
  let key=e.key.toLocaleLowerCase()
  if(CaputredKeys.includes(key)){
    if(!CaputredKeys.includes('shift') && key=='enter'){
      e.preventDefault();
      sendMsg()
    }
    CaputredKeys=CaputredKeys.filter(v=>v!=key)
  }
})

msgContainer.addEventListener("click",({target})=>{
  // console.log(target.className);
  if(target.className=='msgpic'){
    requestAnimationFrame(()=>{
      let {x,y}=target.getBoundingClientRect();
      let {clientHeight,clientWidth}=target;
      let {src}=target;
      prevBox.children[0].src=src;
      document.body.style.setProperty('--prev-top',y+'px');
      document.body.style.setProperty('--prev-left',x+'px');
      document.body.style.setProperty('--prev-width',clientWidth+'px');
      document.body.style.setProperty('--prev-height',clientHeight+'px');
      prevBox.style.display="block"
    })
  }
})

prevBox.onclick=()=>{
  prevBox.style.display="none"
}

/**
 * 
 * @param {*} fn 防抖执行的函数
 * @param {*} delay 
 * @returns debouncedFn
 */
function debounce(fn, delay = 100) {
  let timer = null;
  return function() {
      if (timer) {
          clearTimeout(timer)
      }
      timer = setTimeout(() => {
          fn.apply(this, arguments)
          timer = null
      }, delay)
  }
}
/**
 * 初始化css变量
 */
function initCssVar(){
  // console.log(1111);
  document.body.style.setProperty('--h-max',window.innerHeight +'px')
  document.body.style.setProperty('--w-max',window.innerWidth+'px')
}
/**
 * 发送消息
 */
function sendMsg(){
    let txt=textarea.value;
    txt=txt.replace(/</g,'&lt');
    txt=txt.replace(/>/g,'&gt');
    let timestamp=new Date().getTime();
    let time=dayjs().format('YYYY-MM-DD HH:mm:ss')
    textarea.value="";
    textarea.placeholder="在这里输入";
    let msgObj={userid,userName,txt,time,curentImg,timestamp}
    socket.emit("sendMsg",msgObj);
    appendMsg([msgObj]);
    curentImg='';
    // 消息列表区域滚动置底
    msgContainer.scrollTop=msgContainer.scrollHeight
}
/**
 * 是否拼接Img标签
 * @param {*} o 
 */
function appendImg(o){
  let br=o.txt.length?'<br/>':''
  if(o.curentImg){
    return `
    <img class="msgpic" src="${o.curentImg}"/>${br}
    `
  }else{
    return ''
  }
}

function appendTips(time){
  if(!time){
    msgContainer.innerHTML+=`
      <div class="letter_tip empty mb-20 txt-center">
        暂无聊天记录
      </div>
    `
  }else{
    msgContainer.innerHTML+=`
    <div class="letter_tip mb-20 txt-center">
      ${time}
    </div>
  `
  }
}

/**
 * 追加messageDom结构
 * @param {Array} arr message对象
 */
function appendMsg(arr,isListAppend){
  let len=arr.length,innerHTML='';
  let lastMsgTime=0;
  let lastChild=document.querySelector(".msg_area > .d-flex:last-child");
  lastChild && (lastMsgTime=Number(lastChild.dataset.time));
  //判断是否要添加
  for (let index = 0; index < len; index++) {
    let o=arr[index];
    let extraTipHtml='';
    if(index==0){
      let tipFlag=o.timestamp-lastMsgTime>180000;
      tipFlag && appendTips(o.time);
    }else{
      // 距上次发送时间超过三分种则在message前显示时间
      let prev=arr[index-1]
      let tipFlag=o.timestamp-prev.timestamp>180000;
      tipFlag && (extraTipHtml=`
      <div class="letter_tip mb-20 txt-center">
      ${o.time}
    </div>
      `)
    }
    let bigWrapperClass,smallWrapperClass;
    if(o.userid==userid){
      bigWrapperClass='my';
      smallWrapperClass='r';
    }else{
      bigWrapperClass='single';
      smallWrapperClass='l';
    }
      o.txt=o.txt.replace(/\n/g,'<br/>')
      innerHTML+=`
      ${extraTipHtml}
      <div data-time="${o.timestamp}" class="d-flex ${bigWrapperClass}_content mb-20">
      <div class="head">
        ${o.userName.substring(0,1)}
      </div>
      <div class="content m${smallWrapperClass}-10">
          <p class="uname">${o.userName}</p>
          <div class="msg p-12 mt-5">
            ${appendImg(o)}
            ${o.txt}
          </div>
      </div>
  </div>
      `
  }
  let emptyNode=document.querySelector('.msg_area .empty');
  if(emptyNode){
    msgContainer.removeChild(emptyNode)
  }
  msgContainer.innerHTML+=innerHTML;
}
/**
 * 生成uuid并存入本地
 * 
 */
function generateUUid(){
    if(userid) return;
    userid=uuid.v4();
    !userName && (userName='用户'+userid)
    localStorage.setItem('uuid',userid)
}

/**
 * @name 图片压缩
 * @description
 *  1、将文件转img对象
 *  2、获取文件宽高比例
 *  3、自定义等比例缩放宽高属性，这里我用的是固定800宽度，高度是等比例缩放
 *  4、canvas重新绘制图片
 *  5、canvas转二进制对象转文件对象，返回
 * @returns { File } 文件
 */
async function imgCompress (file,targetWidth=800) {
  // 将文件转img对象
  const img = await fileToImg(file)
  return new Promise((resolve, reject) => {
    const canvas = document.createElement('canvas')
    const context = canvas.getContext('2d')
    // 获取文件宽高比例
    const { width: originWidth, height: originHeight } = img
    // 自定义等比例缩放宽高属性
    const scale = +(originWidth / originHeight).toFixed(2) // 比例取小数点后两位)
    const targetHeight = Math.round(targetWidth / scale) // 等比例缩放高
 
    canvas.width = targetWidth
    canvas.height = targetHeight
    context.clearRect(0, 0, targetWidth, targetHeight)
    // canvas重新绘制图片
    context.drawImage(img, 0, 0, targetWidth, targetHeight)
    // canvas转二进制对象转文件对象，返回
    const type = 'image/png'
    canvas.toBlob(function (blob) {
      const f = new File([blob], file.name, {
        type,
        lastModified: file.lastModified
      })
      resolve(f)
    }, type)
  })
}
 
// file转换成img对象
function fileToImg (file) {
  return new Promise((resolve, reject) => {
    const img = new Image()
    const reader = new FileReader()
    reader.onload = function (e) {
      img.src = e.target.result
    }
    reader.onerror = function (e) {
      reject(e)
    }
    reader.readAsDataURL(file)
    img.onload = function () {
      resolve(img)
    }
    img.onerror = function (e) {
      reject(e)
    }
  })
}